home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
flashdos.asm
< prev
next >
Wrap
Assembly Source File
|
1989-07-29
|
80KB
|
2,715 lines
;*-------------------------------------------------------------------*;
;* FlashDOS Version 2.1 by P.E.Colla 1988 - COLLA @ MARVM1 *;
;* *;
;* This program start a secondary DOS command processor from *;
;* inside applications. *;
;* *;
;* Version 2.0 10-Jul-89 Virtual memory support added. *;
;* Version 2.1 25-Jul-89 Huge mode added. *;
;* *;
;*-------------------------------------------------------------------*;
;*-------------------------------------------------------------------*;
;* DOS Memory Control Block - Chain Record Format (Undocumented) *;
;*-------------------------------------------------------------------*;
mem segment at 0FFFFh
memtype db ?
memid dw ?
memsize dw ?
mem ends
;*-------------------------------------------------------------------*;
;* Main Program Start *;
;*-------------------------------------------------------------------*;
cseg segment para public 'code'
org 100h
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
;*-------------------------------------------------------------------*;
;* Equates *;
;*-------------------------------------------------------------------*;
cr equ 0dh
lf equ 0ah
bell equ 07h
hotkey equ 0Eh
shift_mask equ 08h
ncol equ 80
box_row equ 0
box_col equ 0
bw_attr equ 70h
co_attr equ 17h
id_len equ (id_end - id) - 1
prog_len equ (initialize - main) / 10h
env_var_len equ (env_var_end - env_var)
video_len equ 315
;*-------------------------------------------------------------------*;
;* Control is given here at load time, jump to initialization code *;
;*-------------------------------------------------------------------*;
main: jmp initialize
;*-------------------------------------------------------------------*;
;* Variable definition area *;
;*-------------------------------------------------------------------*;
;***---- COMMON AREA ---***;
;*--- Unique ID to detect multiple load
id db "@#PonchiFlashDOS#@"
id_unique db 10 dup (0)
id_end db 0
;*--- External Swap File Area
swapfile db "A:\FLASHDOS.SWP",0
handle dw ?
;*--- Inter-Process Communication
rc db 00h
;*--- DOS command to be passed to COMMAND.COM at start
dos_command_def db 3," ",cr,0,0
dos_command db 0,40 dup (" "),cr,0,0
command_flag db 0
;*--- Status control area
active db 0
dormant db 0
buffer_type db "I"
huge_mode db 0
;*--- WorkSpace Address & Size
ptr_area dw 0
size_area dw 4096
;*--- Runtime error & messages
merr01 db cr,lf
db "FlashDOS: Invalid Function Code",cr,lf,"$"
merr02 db cr,lf
db "FlashDOS: File not found",cr,lf,"$"
merr05 db cr,lf
db "FlashDOS: Access Denied",cr,lf,"$"
merr07 db cr,lf
db "FlashDOS: Memory Blocks Destroyed",cr,lf,"$"
merr08 db cr,lf
db "FlashDOS: Insufficient memory",cr,lf,"$"
merr09 db cr,lf
db "FlashDOS: Invalid Memory Block Address",cr,lf,"$"
merr10 db cr,lf
db "FlashDOS: Invalid Media",cr,lf,"$"
merr11 db cr,lf
db "FlashDOS: Invalid Format",cr,lf,"$"
merrff db cr,lf
db "FlashDOS: Protection Exception",cr,lf,"$"
merrot db cr,lf
db "FlashDOS: Something wrong occurs",cr,lf,"$"
now_inactive db cr,lf
db "FlashDOS: Now Inactive",cr,lf,"$"
StartUp db cr,lf
db "╔═════════════════════════════════════════════════════════════════════════════╗",cr,lf
db "║ FlashDOS Version 2.1 by P.E.Colla (COLLA @ MARVM1) ║",cr,lf
db "║ Type EXIT to End "
type_msg db "Real"
db "║",cr,lf
db "╚═════════════════════════════════════════════════════════════════════════════╝",cr,lf
db "$"
disk_msg db "Disk"
huge_msg db "Huge"
SwapMsg db cr,lf
db "╔═════════════════════════════════╗",cr,lf
db "║ FlashDOS V2.1 ║",cr,lf
db "║Swapping to Drive "
Drive db "A:"
db ", Please wait║",cr,lf
db "╚═════════════════════════════════╝",cr,lf
db "$"
db " ",cr,lf
Finish db cr,lf
db "FlashDOS Ended",cr,lf,"$"
dos_error db cr,lf
db "FlashDOS: Secondary COMMAND cann't start",cr,lf,"$"
claim_error db cr,lf
db "FlashDOS: Cann't claim memory",cr,lf,"$"
;*--- Errors associated with swap process
emem_error db cr,lf
db "FlashDOS: Memory mgmt error",cr,lf,"$"
epsp_error db cr,lf
db "FlashDOS: PSP do not belong to Usr Program",cr,lf,"$"
edisk_error db cr,lf
db "FlashDOS: Disk error, Can not swap out",cr,lf,"$"
eno_space db cr,lf
db "╔════════════════════════════════╗",cr,lf
db "║ FlashDOS 2.0 ║",cr,lf
db "║ Not enough space to swap ║",cr,lf
db "║ Press any key to continue ║",cr,lf
db "╚════════════════════════════════╝",cr,lf,"$"
eusr_short db cr,lf
db "╔════════════════════════════════╗",cr,lf
db "║ FlashDOS 2.0 ║",cr,lf
db "║ Insufficient User Memory ║",cr,lf
db "║ Press any key to continue ║",cr,lf
db "╚════════════════════════════════╝",cr,lf,"$"
eno_open db cr,lf
db "FlashDOS: Can not open swap file",cr,lf,"$"
eno_swap db cr,lf
db "FlashDOS: Can not swap to file",cr,lf,"$"
eno_shrink db cr,lf
db "FlashDOS: Can not shrink Usr memory",cr,lf,"$"
eswap_ok db cr,lf
db "FlashDOS: User program swapped OK",cr,lf,"$"
eno_retrieve db cr,lf
db "FlashDOS: Can not retrieve memory",cr,lf,"$"
eno_close db cr,lf
db "FlashDOS: Can not close swap file",cr,lf,"$"
eno_erase db cr,lf
db "FlashDOS: Can not erase swap file",cr,lf,"$"
;*--- Local Stack Definition
Old_ss dw ?
Old_sp dw ?
Free_Space dw 512 dup (?)
Loc_sp dw 10 dup (?)
;*--- Interrupt saving area
Old_Int_Area dw 1200 dup (?)
New_Int_Area dw 1200 dup (?)
;*--- EXEC control block
env_segment dw ?
command_ptr dw 2 dup (?)
fcb1_ptr dw 2 dup (?)
fcb2_ptr dw 2 dup (?)
;*--- COMMAND.COM path
comspec_path db "A:\COMMAND.COM",0
db 100 dup (0)
env_var db "COMSPEC="
env_var_end db ?
;*--- User memory block information
usr_base dw ?
usr_psp dw ?
usr_size dw ?
usr_last dw ?
;*--- Swap process auxiliary registers
swp_len dw ?
swp_par dw ?
usr_ptr dw ?
usr_len dw ?
;*--- Stack save area
ss_save dw ?
sp_save dw ?
;*--- Old Interrupt Address
old_int_9 dd 0
old_int_13 dd 0
old_int_21 dd 0
;*--- Video Information
cursor_pos dw 0
display_page db 0
attribute db 0
nrow db 25
;*--- Flags & Status
disk_status db 0
load_flag db 0
dos_flag dd 0
info_ptr dd 00000487h
lo_fn_flag db 0
paragraph_size db 10h
par_size dw 10h
;*-------------------------------------------------------------------*;
;* New BIOS Keyboard Interrupt *;
;*-------------------------------------------------------------------*;
int_9 proc far
assume cs:cseg,ds:nothing,es:nothing,ss:nothing
;*--- Check if Hot Key is pressed
sti
push ax
mov ah,0ffh
mov cs:rc,ah
in al,60h
cmp al,hotkey
jne process_key
mov ah,2
int 16h
and al,0Fh
cmp al,shift_mask
je our_key
;*--- No, continue with old keyboard interrupt handler
process_key:
pop ax
jmp dword ptr cs:old_int_9
;*--- Yes,reset keyboard and see if it is possible to pop up
our_key:
in al,61h
mov ah,al
or al,80h
out 61h,al
jmp short $+2
out 61h,al
cli
mov al,20h
out 20h,al
sti
;*--- Is FlashDOS already active
cmp cs:active,0
jne return_a
;*--- Is DOS in critical state
push ds
push bx
lds bx,cs:dos_flag
cmp byte ptr [bx],0
jne return_b
;*--- Is DOS performing Int 21h greather than 0Ch
cmp cs:lo_fn_flag,0
jne return_b
;*--- Is any disk activity in progress
check_b: cmp cs:disk_status,0
jne return_b
;*--- Is active
cmp cs:dormant,0
je invoke
return_b: pop bx
pop ds
return_a: pop ax
iret
;*--- Condition OK to popup, video condition is saved
invoke: lds bx,cs:info_ptr
lds bx,[bx]
test bl,08h
jnz return_b
mov attribute,co_attr
mov ah,0Fh
int 10h
mov display_page,bh
cmp al,3
jbe mode_ok
mov attribute,bw_attr
cmp al,7
jne return_b
;*--- Set active flag, FlashDOS is not re-entrant.
mode_ok: inc cs:active
;*--- Signal with interprocess purposes that at least the condition for popup
;*--- was completed
mov ah,80h
mov cs:rc,ah
;*--- Put the stack on a safe place and Save everything
cli
mov cs:old_ss,ss
mov cs:old_sp,sp
push cs
pop ss
mov sp,offset cs:Loc_sp
sti
push cx
push dx
push di
push si
push es
push bp
push cs
pop ds
push cs
pop es
;*--- IF External swap mode then preserve interrupt vector and restore the
;*--- vector that was at the FlashDos loading time.
;*--- This operation avoid any conflict if the current program have one or
;*--- more interrupt vectors trapped (pointing to nowhere if swapped).
cmp cs:buffer_type,"E"
jne txintend
cli
push es
mov ax,0000h
mov es,ax
mov si,0000h
lea di,new_int_area
mov bx,1024
txintold:
mov ah,byte ptr es:[si]
mov byte ptr cs:[di],ah
inc di
inc si
dec bx
mov ax,bx
cmp ax,0000h
jne txintold
mov si,0000h
lea di,old_int_area
mov bx,1024
txintnew:
mov ah,byte ptr cs:[di]
mov byte ptr es:[si],ah
inc di
inc si
dec bx
mov ax,bx
cmp ax,0000h
jne txintnew
pop es
sti
txintend:
assume ds:cseg,es:cseg
mov ax,cs
mov ds,ax
mov es,ax
mov ah,3
int 10h
mov cursor_pos,dx
;*--- Save & clear screen
mov di,offset initialize
mov si,0FFFFh
call screen
;*--- If a user program is selected to popup don't clear the screen
cmp byte ptr cs:command_flag,00h
jne dos_ldr
;*--- If external swap is specified don't clear the screen neither
cmp byte ptr cs:buffer_type,"E"
je dos_ldr
call clr_box
;*--- Try to load COMMAND.COM
dos_ldr:
call dos_loader
;*--- Restore screen
mov si,offset initialize
call screen
mov ah,2
mov dx,cursor_pos
int 10h
;*--- Reset active flag
mov active,0
;*--- Restore registers
pop bp
pop es
pop si
pop di
pop dx
pop cx
;*--- Restore Stack
cli
mov ss,old_ss
mov sp,old_sp
sti
;*--- Check if storage mode is external or internal
;*--- If External restore Interrupt Vector area
cmp cs:buffer_type,"E"
jne endint9
cli
push es
mov ax,0000h
mov es,ax
mov si,0000h
lea di,new_int_area
mov bx,1024
reintold:
mov ah,byte ptr cs:[di]
mov byte ptr es:[si],ah
inc di
inc si
dec bx
mov ax,bx
cmp ax,0000h
jne reintold
pop es
sti
;*--- Signal with inter-process purposes that the program sucefully ended
mov ah,00h
mov cs:rc,ah
endint9:
pop bx
pop ds
pop ax
iret
int_9 endp
;*-------------------------------------------------------------------*;
;* Loader of secondary COMMAND.COM *;
;*-------------------------------------------------------------------*;
dos_loader proc near
;*--- Set addresability
mov ax,cs
mov ds,ax
mov es,ax
;*--- Get current video page
mov ah,0Fh
Int 10h
;*--- Position cursor at upper left corner (0,0)
mov bl,00h
mov dx,0000h
mov ah,02h
Int 10h
;*--- Check if Internal or External swap is selected
cmp cs:buffer_type,"E"
je external_swap
;*--- Get pointer to workspace area (If internal swap is active)
internal_storage:
mov ax,word ptr cs:ptr_area
;*--- Freed up reserved workspace area
mov es,ax
mov ah,49h
Int 21h
;*--- OK, go to load command.com
jc intsto01
jmp load_command
;*--- Display error message (never should happen)
intsto01:
mov dx,offset claim_error
call print
jmp escape
;*--- External Swap procedure
external_swap:
;*--- Get current (user program) PSP segment
mov ah,62h
Int 21h
mov cs:usr_psp,bx
;*--- Based on PSP segment address the User's MCB is accesed
push ds
mov ax,cs:usr_psp
dec ax
mov ds,ax
assume ds:mem
;*--- Verify is the MCB is one of the expected type
cmp ds:memtype,"M"
je eswap01
cmp ds:memtype,"Z"
je eswap01
mov dx,offset emem_error
call print
call getkey
pop ds
jmp escape
;*--- Get the owner of the MCB (Should be the PSP just retrieved above)
eswap01:
mov ax,cs:usr_psp
cmp ds:memid,ax
je eswap02
mov dx,offset epsp_error
call print
call getkey
pop ds
jmp escape
;*--- Get the memory size of the block owned by the PSP (in paragraphs)
eswap02:
mov ax,ds:memsize
mov cs:usr_size,ax
;*--- If huge mode is in place the swappable area is set to the user size
;*--- minus one.
cmp byte ptr cs:huge_mode,01h
jnz eswap02b
;*--- The reason to let at least one user block in memory is really to avoid
;*--- the mess to completely erase the user MCB and after the operation
;*--- restore it.
mov ax,word ptr cs:usr_size
sub ax,10h
mov word ptr cs:size_area,ax
assume ds:cseg
eswap02b:
pop ds
;*--- The User PSP size is checked against the size of the area required
cmp ax,size_area
jnb eswap09
mov dx,offset eusr_short
call print
call getkey
jmp escape
;*--- The actual segment from wich the memory will be swapped to disk
;*--- is computed.
;*--- First, the last allocated paragraph is computed
eswap09:
mov ax,cs:usr_psp
dec ax
mov bx,cs:usr_size
add ax,bx
dec ax
mov cs:usr_last,ax
;*--- Now the paragraph in which the swap will start is computed
inc ax
sub ax,cs:size_area
mov cs:usr_base,ax
;*--- All the memory dirty work is already done, now all the user's files
;*--- are closed (if any).
push bx
push cx
mov cx,0Fh
mov bx,05h
eswap03:
mov ah,3Eh
Int 21h
inc bx
loop eswap03
pop cx
pop bx
;*--- Now take a look around to found space enough to swap out the memory
;*--- Scan drive F: thru A:
mov dl,05h
mov dh,00h
;*--- Try to get disk status for the selected drive
eswap04:
clc
mov di,dx
mov al,00h
mov ah,36h
Int 21h
jnc eswap05
mov dx,offset edisk_error
call print
call getkey
jmp escape
;*--- If AX=FFFFh there are no drive available to check
eswap05:
cmp ax,0FFFFh
jne eswap06
;*--- Decrement drive to next available and check again
eswap08:
mov dx,di
dec dl
jnz eswap04
;*--- If drive count reach 0 no one of the drive have enough space to swap
mov dx,offset eno_space
call print
call getkey
jmp escape
eswap06:
;*--- Check if the space available is really huge, otherwise a
;*--- free amount of paragraphs could be greater than FFFFh and
;*--- the space computation could end on error
push ax
mov ax,bx
cmp ax,1000
jge eswap16
jmp eswap17
eswap16:
pop ax
jmp eswap07
;*--- Get free space on drive
;*--- First get bytes on each cluster
eswap17:
pop ax
mul cx
;*--- Then convert to paragraphs by cluster
idiv paragraph_size
mov ah,00h
;*--- Now get total number of paragraphs available on drive
mul bx
;*--- Compare with amount needed, if not enough continue to cycle
cmp ax,size_area
jnb eswap07
jmp eswap08
eswap07:
;*--- Now the drive with sufficient space is on DI, transfer to DX
mov dx,di
;*--- Convert the drive number to a useful form
add dl,40h
mov cs:swapfile,dl
mov cs:drive,dl
;*--- Print swap in progress message
mov ax,cs
mov ds,ax
mov dx,offset SwapMsg
call print
;*--- Create and open the swapfile (hidden file)
push cs
pop ds
mov dx,offset swapfile
mov cx,02h
mov ah,03cH
Int 21h
jnc eswap10
mov dx,offset eno_open
call print
call getkey
jmp escape
;*--- Store the handle number returned by DOS
eswap10:
mov cs:handle,ax
;*--- Now the swap is actually done
;*--- Set the address FROM
mov ax,cs:usr_base
mov cs:usr_ptr,ax
;*--- Set the size to swap
mov ax,size_area
mov usr_len,ax
;*--- Cycle thru the swapable area swapping on 64K chunks
eswap11:
mov bx,usr_len
mov ax,0fffh
cmp ax,bx
jb more_64K
mov ax,usr_len
mul par_size
mov swp_len,ax
mov swp_par,bx
jmp swap_in
more_64K:
mov ax,0FFF0h
mov swp_len,ax
mov ax,0fffh
mov swp_par,ax
swap_in:
clc
mov bx,handle
mov cx,swp_len
mov dx,0000h
push ds
mov ax,usr_ptr
mov ds,ax
mov ah,40h
mov al,00h
Int 21h
pop ds
jnc eswap12
;*--- Check if the amount of bytes wrote is equal than expected
mov dx,offset eno_swap
call print
call getkey
jmp escape
;*--- Increment pointer (next paragraph) decrement remaining size
eswap12:
mov ax,usr_ptr
add ax,swp_par
mov usr_ptr,ax
mov ax,usr_len
sub ax,swp_par
mov usr_len,ax
;*--- When remainder is equal to zero the swap is finished
cmp ax,0000h
jne eswap11
cmp byte ptr cs:command_flag,00h
jne eswap18
;*--- Clear Screen & Position cursor at upper left corner (0,0)
push ds
push es
call clr_box
mov bl,00h
mov dx,0000h
mov ah,02h
Int 10h
pop es
pop ds
;*--- To complete the swap the swapfile is closed
eswap18:
clc
mov bx,cs:handle
mov ah,3Eh
Int 21h
jnc eswap15
mov dx,offset eno_close
call print
call getkey
jmp escape
;*--- When the swap is complete the piece of the user program swaped is
;*--- shrinked down to allow free space to be used.
eswap15:
mov ax,usr_size
sub ax,size_area
mov bx,ax
mov ax,usr_psp
mov es,ax
mov ah,4ah
mov al,00h
Int 21h
jnc load_command
mov dx,offset eno_shrink
call print
call getkey
jmp escape
load_command:
;*--- Set contents of EXEC Control Block
mov ax,word ptr cs:2Ch
mov env_segment,ax
mov word ptr cs:env_segment + 4,cs
;*--- Select between default or specified DOS Command
cmp command_flag,00h
je default_com
mov word ptr cs:env_segment + 2,offset dos_command
jmp start_load
default_com:
mov word ptr cs:env_segment + 2,offset dos_command_def
;*--- Save main registers on stack
start_load:
push es
push ds
push bp
;*--- Save stack itself
mov ss_save,ss
mov sp_save,sp
;*--- Display PopUp message
cmp byte ptr cs:command_flag,00h
jne cont_load
mov ax,cs
mov ds,ax
mov dx,offset StartUp
call print
;*--- Load & Exec a Secondary DOS Command Processor
cont_load:
mov ax,cs
mov ds,ax
mov es,ax
lea dx,comspec_path
lea bx,env_segment
mov ah,4bh
mov al,00h
Int 21h
;*--- Restore stack & registers
mov ss,ss_save
mov sp,sp_save
pop bp
pop ds
pop es
;*--- Something wrong? , Display message.
jc load_error
end_load:
cmp byte ptr cs:command_flag,00h
jne end_ldb
;*--- Display End Session message
mov dx,offset Finish
call print
end_ldb:
cmp cs:buffer_type,"E"
je external_retrieve
;*--- If internal swap done Allocate workspace again to preserve it.
internal_retrieve:
mov ax,cs
mov ds,ax
mov es,ax
mov bx,size_area
mov ah,48h
Int 21h
;*--- Cann't, display message.
jc prt_mem_err
;*--- Workspace is under ownership of the interrupted program
;*--- Access DOS Memory Control Block of allocated space and change
;*--- ID to point to PSP of FlashDOS.
mov word ptr cs:ptr_area,ax
dec ax
mov ds,ax
assume ds:mem
cmp ds:memtype,"M"
jne chg_mem_err
mov ax,cs
mov ds:memid,ax
;*--- Restablish addresability
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
mov ax,cs
mov ds,ax
jmp escape
;*--- Error handling & display messages
chg_mem_err:
mov ax,0ffh
prt_mem_err:
call memory_error
;*--- Cann't claim back its memory, became inactive
mov dormant,01h
mov dx,offset now_inactive
call print
jmp escape
;*--- If load error is found after the message the workarea is claimed again
load_error:
call memory_error
call getkey
jmp end_load
;*--- If external retrieve is active the memory is swapped back
external_retrieve:
;*--- Last, the Usr program is restored as a main PSP for DOS
push cs
pop ax
mov es,ax
mov ds,ax
;*--- The user memory block is restored to his original size
clc
mov ax,usr_size
mov bx,ax
mov ax,usr_psp
mov es,ax
mov ah,4ah
mov al,00h
Int 21h
jnc eretr01
mov dx,offset eno_retrieve
call print
call getkey
jmp escape
eretr01:
;*--- Now the swapfile is open for read
clc
push cs
pop ds
mov dx,offset swapfile
mov ax,3D00h
Int 21h
jnc eretr02
mov dx,offset eno_open
call print
call getkey
jmp escape
;*--- If the file was sucefully open the swaped part of the memory is restored
eretr02:
mov cs:handle,ax
push cs
pop ax
mov es,ax
mov ds,ax
mov ax,usr_base
mov usr_ptr,ax
mov ax,size_area
mov usr_len,ax
eretr03:
mov bx,usr_len
mov ax,0fffh
cmp ax,bx
jb more_64Kb
mov ax,usr_len
mul par_size
mov swp_len,ax
mov swp_par,bx
jmp swap_out
more_64Kb:
mov ax,0FFF0h
mov swp_len,ax
mov ax,0fffh
mov swp_par,ax
swap_out:
clc
mov bx,handle
mov cx,swp_len
mov dx,0000h
push ds
mov ax,usr_ptr
mov ds,ax
mov al,00h
mov ah,3Fh
Int 21h
pop ds
jnc eretr04
mov dx,offset eno_swap
call print
call getkey
jmp escape
eretr04:
mov ax,usr_ptr
add ax,swp_par
mov usr_ptr,ax
mov ax,usr_len
sub ax,swp_par
mov usr_len,ax
cmp ax,0000h
je eretr04b
jmp eretr03
;*--- If the swap back ends sucefully the swapfile is closed
eretr04b:
mov bx,handle
mov ah,3Eh
Int 21h
jnc eretr05
mov dx,offset eno_close
call print
call getkey
jmp escape
eretr05:
;*--- Just to be clean the swapfile is erased from the disk
clc
push cs
pop ds
mov dx,offset swapfile
mov ah,41h
Int 21h
jnc escape
mov dx,offset eno_erase
call print
call getkey
jmp escape
escape:
ret
dos_loader endp
;*-------------------------------------------------------------------*;
;* Wait for any key to be pressed *;
;*-------------------------------------------------------------------*;
getkey proc near
mov ah,1
int 16h
jne getkey1
jmp getkey
getkey1: mov ah,0
int 16h
ret
getkey endp
;*-------------------------------------------------------------------*;
;* Save/Restore Screen *;
;*-------------------------------------------------------------------*;
screen proc near
cld
mov bh,display_page
mov ch,00
mov cl,nrow
mov dh,box_row
row_loop:
push cx
mov cx,ncol
mov dl,box_col
col_loop:
push cx
mov ah,2
int 10h
cmp si,0FFFFh
je do_save
lodsw
mov bl,ah
mov ah,9
mov cx,01
int 10h
jmp short do_loop
do_save:
mov ah,8
int 10h
stosw
do_loop:
inc dl
pop cx
loop col_loop
pop cx
inc dh
loop row_loop
ret
screen endp
;*-------------------------------------------------------------------*;
;* Clear Screen and Set Color *;
;*-------------------------------------------------------------------*;
clr_box proc near
mov ax,0600h
mov ch,box_row
mov cl,box_col
mov dh,box_row - 1
add dh,nrow
mov dl,box_col + ncol - 1
mov bh,attribute
int 10h
ret
clr_box endp
;*-------------------------------------------------------------------*;
;* New Disk BIOS Interrupt Handler *;
;*-------------------------------------------------------------------*;
int_13 proc far
assume ds:nothing,es:nothing
mov cs:disk_status,1
pushf
call dword ptr cs:old_int_13
mov cs:disk_status,0
sti
ret 2
int_13 endp
;*-------------------------------------------------------------------*;
;* New Main DOS Interrupt Handler *;
;*-------------------------------------------------------------------*;
int_21 proc far
mov cs:lo_fn_flag,0
cmp ah,0
jne check
mov ah,4Ch
go_direct:
jmp dword ptr cs:old_int_21
check:
cmp ah,0ch
ja go_direct
inc cs:lo_fn_flag
pushf
call dword ptr cs:old_int_21
mov cs:lo_fn_flag,0
ret 2
int_21 endp
;*-------------------------------------------------------------------*;
;* Handler of process errors *;
;*-------------------------------------------------------------------*;
memory_error proc near
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
push ds
push ax
mov ax,cs
mov ds,ax
pop ax
cmp ax,01h
je err_mem_01h
cmp ax,02h
je err_mem_02h
cmp ax,05h
je err_mem_05h
cmp ax,10
je err_mem_10h
cmp ax,11
je err_mem_11h
cmp ax,07h
je err_mem_07h
cmp ax,08h
je err_mem_08h
cmp ax,09h
je err_mem_09h
cmp ax,0ffh
je err_mem_ffh
err_mem_oth:
mov dx,offset merrot
call print
jmp end_memory
err_mem_07h:
mov dx,offset merr07
call print
jmp end_memory
err_mem_01h:
mov dx,offset merr01
call print
jmp end_memory
err_mem_02h:
mov dx,offset merr02
call print
jmp end_memory
err_mem_05h:
mov dx,offset merr05
call print
jmp end_memory
err_mem_10h:
mov dx,offset merr10
call print
jmp end_memory
err_mem_11h:
mov dx,offset merr11
call print
jmp end_memory
err_mem_08h:
mov dx,offset merr08
call print
jmp end_memory
err_mem_09h:
mov dx,offset merr09
call print
jmp end_memory
err_mem_ffh:
mov dx,offset merrff
call print
jmp end_memory
end_memory:
call getkey ;Version 2.0
pop ds
ret
memory_error endp
;*-------------------------------------------------------------------*;
;* Routine to convert from binary to ASCII (Hex Format) *;
;*-------------------------------------------------------------------*;
L0154 proc near
push cx
mov cx,4
mov ah,0
rol ax,cl
ror al,cl
L015E: add al,30h;'0'
cmp al,39h;'9'
jle L0166
add al,7
L0166: cmp ch,0
je L016D
xchg al,ah
pop cx
ret
L016D: mov ch,1
xchg al,ah
jmp L015E
L0154 endp
;*-------------------------------------------------------------------*;
;* Print String - BIOS based version of Int 21h Fn=09h *;
;*-------------------------------------------------------------------*;
print proc near
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
push es
push ds
push ax
push dx
push si
push bx
push cx
mov ax,dx
mov si,ax
mov ax,cs
mov ds,ax
print_loop:
cmp byte ptr cs:[si],"$"
je eprint
mov ah,0Fh
Push si
Int 10h
Pop si
mov bl,00h
mov al,byte ptr cs:[si]
mov ah,0eh
Push si
Int 10h
Pop si
inc si
jmp print_loop
eprint:
pop cx
pop bx
pop si
pop dx
pop ax
pop ds
pop es
ret
print endp
;*-------------------------------------------------------------------*;
;* Main Initialization code *;
;*-------------------------------------------------------------------*;
initialize proc near
assume cs:cseg,ds:cseg,es:nothing,ss:cseg
;*--- Set addresability & Display Copyright notice
mov ax,cs
mov ds,ax
mov es,ax
mov dx,offset copyright
call print
;*--- Check if DOS version is greater than 2.00
push es
push ds
mov ah,30h
Int 21h
cmp al,02h
jge next_init
;*--- No, message error and terminate
mov load_flag,0
mov dx,offset wrong_dos
call print
pop ds
pop es
jmp no_load
next_init:
pop ds
pop es
mov word ptr [main+0],0
mov word ptr [main+2],0
;*--- Search for copies of itself on DOS memory chain
xor bx,bx
mov ax,cs
next_para:
inc bx
cmp ax,bx
mov es,bx
je end_search
mov si,offset id
mov di,si
mov cx,id_len
rep cmpsb
or cx,cx
jnz next_para
;*--- Another copy was founded, send message and prevent to load again
;*--- also, the segment in wich the previous copy was founded is saved
mov load_flag,0
mov ax,es
mov curr_segm,ax
mov dx,offset yet_loaded
call print
jmp get_parm
end_search:
;*--- No another copy can be founded, prosecute installation
mov load_flag,1
;*--- In ES is stored the current CS segment , save it
mov ax,es
mov curr_segm,ax
;*--- Now command parameters are inspected
get_parm:
;*--- Point to first character of parameter area in the PSP
mov si,81h
push cs
pop ds
;*--- Throw away if blank
parse:
cmp ds:byte ptr [si],32
jne parse1
inc si
jmp parse
;*--- If first non-blank is carriage return the command area is empty
;*--- Load with default memory size of 4096 paragraphs
parse1:
cmp ds:byte ptr [si],cr
jne parseus
jmp locate_com
;*--- First non-blank is "/" or is an error
parseus:
cmp ds:byte ptr [si],2Fh
je parnum
jmp error_parm
;*--- Try to convert parameter from ASCII to binary
parnum:
push si
inc si
mov ax,si
mov dx,ax
mov ax,cs
mov ds,ax
call cnvd2h
cmp ax,0000h
je parsest
;*--- Sucefull conversion, the number is stored as a requested memory size
lea di,size_area
mov word ptr cs:[di],ax
pop si
;*--- If there are another copy on memory try to change it workspace size
cmp load_flag,1
jne parsesi
jmp locate_com
;*--- First check if it is inactive, this would ensure that there are no
;*--- workspace allocated to it
parsesi:
mov ax,curr_segm
mov es,ax
cmp es:dormant,01h
je parses1
jmp locate_com
parses1:
;*--- The newest size area is stamped on the resident copy and the control
;*--- is transfered to the regular activation procedure
mov ax,word ptr cs:size_area
mov word ptr es:size_area,ax
jmp activation
;*--- The parameter is in valid format but it is not a number
;*--- check if is one of /H,/U,/I,/E,/A or /?
parsest:
;*--- Restore SI register just to clean up the stack
pop si
parse0:
;*--- Force UpperCase
mov ah,ds:byte ptr [si+1]
mov ar,ah
and ds:byte ptr [si+1],0DFh
;*--- Is /E , Then is an External Swap indication
cmp ds:word ptr [si],452Fh
jne parse1b
jmp set_ext
;*--- Is /H , Then is a Huge Mode indication
parse1b:
cmp ds:word ptr [si],482Fh
jne parse1a
jmp set_huge
;*--- Is /A , Then is an Activation Request
parse1a:
cmp ds:word ptr [si],412Fh
jne parse2
jmp activation
;*--- Is /U , Then is an UnInstall request
parse2:
cmp ds:word ptr [si],552Fh
jne parse3
jmp uninstall
;*--- Is /I , Then is an Inactivation request
parse3:
cmp ds:word ptr [si],492Fh
jne parse4
jmp inactivation
;*--- Is /? , Then display a help text
parse4:
mov ah,ar
mov byte ptr ds:[si+1],ah
cmp ds:word ptr [si],3F2Fh
jne parse5
jmp help
;*--- Is /C , Then search for filename
parse5:
and ds:byte ptr [si+1],0DFh
cmp ds:word ptr [si],432Fh
je user_spec
mov dx,offset invalid_parm
call print
jmp locate_com
;*--- Establish huge mode (automatically set external swap mode)
set_huge:
mov byte ptr es:huge_mode,01h
;*--- Print message telling about the huge selection
mov dx,offset huge_mode_msg
call print
;*--- Save the position on the command line
push si
;*--- Put a message telling about the Huge mode in the wakeup message
lea di,es:type_msg
lea si,es:huge_msg
mov al,04h
set_hugea:
mov ah,byte ptr ds:[si]
mov byte ptr ds:[di],ah
inc si
inc di
dec al
cmp al,00h
jne set_hugea
;*--- Restore the position on the command line
pop si
jmp set_ext
;*--- get address of dos_command buffer & reset counter
user_spec:
mov di,offset dos_command
mov byte ptr es:[di],00h
push di
xor ah,ah
inc di
;*--- Transfer command line till the CR
user_01:
cmp byte ptr [si],cr
je end_user
mov al,byte ptr [si]
mov es:byte ptr [di],al
inc si
inc di
inc ah
cmp byte ptr [si],"/"
je end_user
jmp user_01
;*--- Store correct values on flag,counter
end_user:
mov es:byte ptr [di],cr
pop di
mov es:byte ptr [di],ah
mov ah,01h
mov es:byte ptr command_flag,ah
mov dx,offset user_file
call print
jmp parse
;*--- Display help text and exit without being resident
help:
mov dx,offset flash_help
call print
mov load_flag,0
jmp no_load
;*--- Invalid parameter is given, display error and exit
error_parm:
mov dx,offset invalid_parm
call print
mov load_flag,0
jmp no_load
;*--- Set external swap flag
set_ext:
mov ax,curr_segm
mov es,ax
mov byte ptr es:buffer_type,"E"
mov dx,offset exter_stor
call print
inc si
inc si
push si
push di
push bx
;*--- If huge mode is active the message was already moved
cmp byte ptr es:huge_mode,01h
jz set_extb
;*--- Transfer the regular disk message
lea di,es:type_msg
lea si,es:disk_msg
mov al,04h
set_exta:
mov ah,byte ptr ds:[si]
mov byte ptr ds:[di],ah
inc si
inc di
dec al
cmp al,00h
jne set_exta
set_extb:
;*--- When the external mode is selected additional provisions must be taken
;*--- to ensure that any code in the swapped part IS NOT part of an
;*--- interruption.
;*--- The safest way is to save the interrupt status in this moment and
;*--- swap back and forth this one when Flashdos is invoked.
push es
mov ax,0000h
mov es,ax
mov si,0000h
lea di,ds:old_int_area
mov bx,1024
reintnew:
mov ah,byte ptr es:[si]
mov byte ptr ds:[di],ah
inc di
inc si
dec bx
mov ax,bx
cmp ax,0000h
jne reintnew
pop es
pop bx
pop di
pop si
jmp parse
;*--- Activation request
activation:
cmp load_flag,0
je activ01
;*--- Cann't activate if it is not in memory
mov dx,offset no_loaded
call print
mov load_flag,0
jmp no_load
;*--- See if it is yet active
activ01:
mov ax,curr_segm
mov es,ax
cmp byte ptr es:dormant,0
jne activ02
;*--- Is already active, you cann't active it again
mov dx,offset yet_active
call print
mov load_flag,0
jmp no_load
;*--- The program is resident and inactive, so active it
;*--- Program Owns all the memory, shrink it to a minimun if internal swap
activ02:
cmp es:buffer_type,"E"
je activ05
mov ax,cs
mov bx,prog_len
add bx,video_len
push es
mov es,ax
mov ah,4Ah
int 21h
pop es
jnc activ03
call memory_error
mov load_flag,1
jmp no_load
activ03:
;*--- Get workspace area, save the returned pointer for future use
mov ax,cs
mov ds,ax
mov bx,es:size_area
mov ah,48h
push es
Int 21h
pop es
jnc activ04
call memory_error
mov load_flag,1
jmp no_load
activ04:
;*--- The work memory was claimed suceffully store pointer
mov word ptr es:ptr_area,ax
;*--- The memory claimed is under the property of the running FlashDOS and
;*--- not of the resident portion, some DOS memory block adjusting is in place
push es
push ds
mov word ptr es:ptr_area,ax
dec ax
mov ds,ax
assume ds:mem
cmp ds:memtype,"M"
jne act_mem_err
mov ax,es
mov ds:memid,ax
pop ds
pop es
;*--- Restablish addresability
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
activ05:
mov ax,cs
mov ds,ax
;*--- Change active flag to active
mov byte ptr es:dormant,0
;*--- Send message and exit
mov dx,offset now_active
call print
mov load_flag,0
jmp no_load
;*--- Display memory management problem and exit
act_mem_err:
mov ax,0ffh
call memory_error
mov load_flag,0
jmp no_load
;*--- Inactivation Request
inactivation:
call set_inactive
jmp no_load
;*--- UnInstall Request
Uninstall:
cmp load_flag,0
je unins01
;*--- Cann't uninstall if it is not in memory
mov dx,offset no_loaded
call print
mov load_flag,0
jmp no_load
;*--- See if it is active or inactive
unins01:
mov ax,curr_segm
mov es,ax
cmp byte ptr es:dormant,0
jne unins02
;*--- Cann't uninstall if it is not inactive
push es
call set_inactive
pop es
;*--- Now, check if all interrupts trapped still pointing to myself
unins02:
;*--- Interrupt 09h (Keyboard) is verified against resident segment
push es
mov ah,35h
mov al,09h
Int 21h
mov bx,es
pop es
mov ax,es
cmp bx,ax
je int09_ok
;*--- Is different, cann't uninstall
mov dx,offset wrong_int09
call print
mov load_flag,0
jmp no_load
int09_ok:
;*--- Interrupt 13h (BIOS Disk) is verified against resident segment
push es
mov ah,35h
mov al,13h
Int 21h
mov bx,es
pop es
mov ax,es
cmp bx,ax
je int13_ok
;*--- Is different, cann't uninstall
mov dx,offset wrong_int13
call print
mov load_flag,0
jmp no_load
int13_ok:
;*--- Interrupt 21h (DOS Function) is verified against resident segment
push es
mov ah,35h
mov al,21h
Int 21h
mov bx,es
pop es
mov ax,es
cmp bx,ax
je int21_ok
;*--- Is different, cann't uninstall
mov dx,offset wrong_int21
call print
mov load_flag,0
jmp no_load
int21_ok:
;*--- All trapped interrupts belong to FlashDOS so restore old values
;*--- Restore Int09h
push es
lds dx,es:old_int_9
mov ah,25h
mov al,09h
Int 21h
pop es
;*--- Restore Int13h
push es
lds dx,es:old_int_13
mov ah,25h
mov al,13h
Int 21h
pop es
;*--- Restore Int21h
push es
lds dx,es:old_int_21
mov ah,25h
mov al,21h
Int 21h
pop es
;*--- Corrupt the signature, otherwise another try to load FlashDOS would fail
xor ax,ax
mov es:id,al
;*--- Now resident FlashDOS is a dead memory zone, release environment
push es
mov ax,word ptr es:2Ch
mov es,ax
mov ah,49h
Int 21h
pop es
;*--- Release resident program itself
push es
mov ah,49h
Int 21h
pop es
;*--- Uninstallation complete, display a message
mov dx,offset now_uninstall
call print
mov load_flag,0
jmp no_load
;*--- Get the current COMMAND.COM path from the Environment Block
locate_com:
;*--- Check if there are another copy in memory
cmp load_flag,0
jne loc_com
jmp no_load
;*--- Inspect environment area
loc_com:
push es
mov ax,word ptr cs:2Ch
mov es,ax
mov ax,offset env_var
mov si,ax
mov cx,env_var_len
call Get_Env_Str
cmp al,00h
jne no_comm_found
mov ax,offset comspec_path
mov si,ax
locate_loop:
mov al,byte ptr es:[di]
cmp al,00h
je end_locate
mov byte ptr cs:[si],al
inc si
inc di
jmp locate_loop
end_locate:
mov byte ptr cs:[si],al
;*--- No 'COMSPEC' variable can be found in the environment
no_comm_found:
pop es
continue:
;*--- Program Owns all the memory, shrink it to a minimun
mov ax,cs
mov es,ax
mov bx,prog_len
add bx,video_len
mov ah,4Ah
int 21h
jnc cont01
call memory_error
mov load_flag,1
jmp no_load
cont01:
;*--- If internal get workspace area, save the returned pointer for future use
cmp buffer_type,"E"
je cont02b
mov ax,cs
mov ds,ax
mov bx,size_area
mov ah,48h
Int 21h
jnc cont02
call memory_error
mov load_flag,1
jmp no_load
cont02:
mov word ptr cs:ptr_area,ax
;*--- Get the DOS Critical Flag Address (Undocumented)
cont02b:
mov ah,34h
int 21h
mov word ptr dos_flag[0],bx
mov word ptr dos_flag[2],es
;*--- Trap Int 09h, 10h and 21h
push ds
pop es
mov al,9
mov di,offset old_int_9
mov dx,offset int_9
call set_int
mov al,13h
mov di,offset old_int_13
mov dx,offset int_13
call set_int
mov al,21h
mov di,offset old_int_21
mov dx,offset int_21
call set_int
;*--- Main initializacion job done, so print message
mov dx,offset loaded_ok
call print
;*--- Get pointer to workspace and convert binary to ASCII, print it.
cmp buffer_type,"E"
je cont03a
mov ax,word ptr cs:ptr_area
call L0154
mov MSBH,ah
mov MSBL,al
mov ax,ptr_area
mov al,ah
call L0154
mov LSBH,ah
mov LSBL,al
mov dx,offset mem_ptr
call print
;*--- Get workspace size in paragraphs and convert binary to ASCII, print it.
cont03a:
;*--- If it is on huge mode the workspace size doesn't matter.
cmp byte ptr cs:huge_mode,01h
jz tsr_pgm
mov ax,word ptr cs:size_area
call L0154
mov MMSBH,ah
mov MMSBL,al
mov ax,size_area
mov al,ah
call L0154
mov MLSBH,ah
mov MLSBL,al
mov dx,offset mem_size
call print
;*--- Terminate and Stay Resident
tsr_pgm:
mov dx,prog_len
add dx,video_len
mov ax,3100h
int 21h
;*--- Procedure to avoid to keep as a TSR
no_load:
mov dx,offset not_loaded
call print
mov al,04h
mov ah,4ch
Int 21h
initialize endp
;*-------------------------------------------------------------------*;
;* Routine to Trap current interrupt and set the own one *;
;*-------------------------------------------------------------------*;
set_int proc near
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
push ax
mov ah,35h
int 21h
mov word ptr [di+0],bx
mov word ptr [di+2],es
pop ax
mov ah,25h
int 21h
ret
set_int endp
;*-------------------------------------------------------------------*;
;*GET_ENV_STR procedure to find a string in the environment *;
;*Input: ES pointer to environment *;
;* SI pointer to variable to find plus equals sign *;
;* CX length of variable including equals sign *;
;*Output: DI pointer to start of value of variable, if AL=0 *;
;* AL 0 if string found, 1 if not *;
;* ES,SI,CX unchanged *;
;*Borrowed from ENVPTR Package by Jeff Urs from PCTOOLS *;
;*-------------------------------------------------------------------*;
Get_Env_Str: Sub DI,DI
Cld
End_Check: Cmp Byte Ptr ES:[DI],00
Jne Check_Str
Mov AL,1
Jmp Short Get_Env_End
Check_Str: Push SI
Push CX
Repe Cmpsb
Pop CX
Pop SI
Jne Next_Str
Xor AL,AL
Jmp Short Get_Env_End
Next_Str: Xor AL,AL
Push CX
Mov CX,8000H
Repne Scasb
Pop CX
Jmp End_Check
;
Get_Env_End: Ret
;*-------------------------------------------------------------------*;
;* CNVD2H: This routine will convert a decimal string into a hex-*;
;* adecimal word value. The user passes a pointer to a string *;
;* containing a value between -32768 and 65535. *;
;* *;
;* INPUT: DS:DX - number string to convert *;
;* OUTPUT: AX - output value *;
;* *;
;* All registers are preserved except AX. *;
;* *;
;* Written by G. R. Ingalls - 4/29/87 *;
;*-------------------------------------------------------------------*;
cnvd2h proc near
;*--- Save Registers
push bx
push cx
push dx
push es
push di
push si
;*--- Scan charater string to be converted
mov si,dx
mov bl,1
get_sign:
;*--- Check for first non-blank character
lodsb
cmp al,' '
je get_sign
;*--- If a sign is founded (+ or -) save it
cmp al,'+'
jne chk_minus_sign
jmp got_sign
chk_minus_sign:
cmp al,'-'
jne no_sign
mov bl,-1
jmp got_sign
no_sign:
;*--- Restore character pointer
dec si
got_sign:
push bx
;*--- For each numeric character add it to the result, stop at first non num
;*--- Clear CX to store results
xor cx,cx
next_character:
lodsb
;*--- Check if it is numeric value
cmp al,'0'
jb not_numeric
cmp al,'9'
ja not_numeric
;*--- Convert to binary
sub al,'0'
cbw
xchg ax,cx
mov bx,10
mul bx
;*--- Add to counter
add ax,cx
xchg ax,cx
jmp next_character
not_numeric:
;*--- Set the proper sign ;
pop bx
cmp bl,-1
jne not_negative
neg cx
not_negative:
;*--- Put result in AX and exit ;
mov ax,cx
pop si
pop di
pop es
pop dx
pop cx
pop bx
ret
cnvd2h endp
;*-------------------------------------------------------------------*;
;* Proc to inactivate the program, shared by inactive and uninstall *;
;*-------------------------------------------------------------------*;
set_inactive proc near
cmp load_flag,0
je inact01
;*--- Cann't inactivate if it is not in memory
mov dx,offset no_loaded
call print
mov load_flag,0
ret
;*--- See if it is yet inactive
Inact01:
mov ax,curr_segm
mov es,ax
cmp byte ptr es:dormant,1
jne Inact02
;*--- Is already inactive, you cann't inactive it again
mov dx,offset yet_inactive
call print
mov load_flag,0
ret
;*--- Is resident and active, inactive and freed memory buffer
Inact02:
mov byte ptr es:dormant,1
;*--- If external swap is required don't mess with the memory
cmp es:buffer_type,"E"
je inact03
;*--- Get pointer to workspace area
mov ax,word ptr es:ptr_area
;*--- Freed up reserved workspace area
mov es,ax
mov ah,49h
Int 21h
;*--- OK, display message and end
jc cannt_inactive
inact03:
mov dx,offset now_inactive
call print
mov load_flag,0
ret
;*--- Something wrongs occurs, FlashDOS cann't free up the memory
cannt_inactive:
call memory_error
mov byte ptr es:dormant,0
mov load_flag,0
ret
set_inactive endp
;*-------------------------------------------------------------------*;
;* Messages and variables used during initialization process only *;
;*-------------------------------------------------------------------*;
curr_segm dw ?
not_loaded db cr,lf
db "FlashDOS: Not Loaded",cr,lf,"$"
loaded_ok db cr,lf
db "FlashDOS: Loaded sucefully",cr,lf,"$"
yet_loaded db cr,lf
db "FlashDOS: Already Loaded",cr,lf,"$"
yet_active db cr,lf
db "FlashDOS: Already Active",cr,lf,"$"
yet_inactive db cr,lf
db "FlashDOS: Already Inactive",cr,lf,"$"
now_active db cr,lf
db "FlashDOS: Now Active",cr,lf,"$"
exter_stor db cr,lf
db "FlashDOS: External Storage Selected",cr,lf,"$"
now_uninstall db cr,lf
db "FlashDOS: Uninstalled sucefully",cr,lf,"$"
mem_ptr db cr,lf,"FlashDOS: Memory area allocated at "
LSBH db "0"
LSBL db "0"
MSBH db "0"
MSBL db "0"
db ":0000h",cr,lf,"$"
mem_size db cr,lf,"FlashDOS: Memory size "
MLSBH db "0"
MLSBL db "0"
MMSBH db "0"
MMSBL db "0"
db "h Paragraphs",cr,lf,"$"
copyright db cr,lf
db "╔══════════════════════════╗",cr,lf
db "║FlashDOS V2.1 by P.E.Colla║",cr,lf
db "║ IBM Internal Use Only ║",cr,lf
db "║ DOS Switch ║",cr,lf
db "║ COLLA @ MARVM1 ║",cr,lf
db "║Press Alt-Backspace to Pop║",cr,lf
db "╚══════════════════════════╝",cr,lf
db "$"
huge_mode_msg db cr,lf
db "FlashDOS: Huge Mode Selected",cr,lf,"$"
user_file db cr,lf
db "FlashDOS: User File Defined",cr,lf,"$"
wrong_dos db cr,lf
db "FlashDOS: Incorrect DOS Level",cr,lf,"$"
wrong_int09 db cr,lf
db "FlashDOS: Unable to restore Int 09h.",cr,lf,"$"
wrong_int13 db cr,lf
db "FlashDOS: Unable to restore Int 13h.",cr,lf,"$"
wrong_int21 db cr,lf
db "FlashDOS: Unable to restore Int 21h.",cr,lf,"$"
must_inactive db cr,lf
db "FlashDOS: Must be inactive to Uninstall",cr,lf,"$"
no_loaded db cr,lf
db "FlashDOS: Not previously loaded.",cr,lf,"$"
invalid_parm db cr,lf
db "FlashDOS: Incorrect parameter, type FlashDOS /?"
db " for help.",cr,lf,"$"
flash_help db cr,lf
db " FlashDOS Version 2.1 by P.E.Colla 1988 ",cr,lf
db "This program start a secondary DOS command",cr,lf
db "processor from inside another application.",cr,lf
db "Using it you can manage a limited kind of ",cr,lf
db "multitasking. At loading time the user must",cr,lf
db "specify if memory or disk swap is desired.",cr,lf
db "To invoke them type: ",cr,lf
db " FLASHDOS /{Switch} ",cr,lf
db "Valid Switches values are: ",cr,lf
db " /? Help ",cr,lf
db " /E Swap to disk ",cr,lf
db " /I Inactive Request (Shrink Memory)",cr,lf
db " /A Active Request (Growth memory) ",cr,lf
db " /U Un-Install (became /I if cann't)",cr,lf
db " /H Active Huge Mode ",cr,lf
db " /C Pgm Install Program as a TSR ",cr,lf
db " /99999 Size in paragraphs of internal ",cr,lf
db " memory area (default 64k bytes)",cr,lf
db "The program will not PopUp when you are on",cr,lf
db "graphics video mode or at DOS prompt. ",cr,lf
db " COLLA @ MARVM1 ",cr,lf
db "$"
ar db ?
free db "#"
cseg ends
end main